package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strconv"
	"time"

	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/config"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/httphandler"
	dwr "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dwr/v3"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dwr/v3/model"
)

const (
	endpoint                   = "endpoint"
	ak                         = "access_key"
	sk                         = "secret_key"
	projectId                  = "projectId"
	funcPkgPath                = ""
	funcHelpPathEn             = ""
	funcHelpPathCn             = ""
	funcLogoPathEn             = ""
	funcLogoPathCn             = ""
	funcSlaPathEn              = ""
	funcSlaPathCn              = ""
	funcTestReportPathEn       = ""
	funcTestReportPathCn       = ""
	funcOpensourceNoticePathEn = ""
	funcOpensourceNoticePathCn = ""
)

func uploadAllFuncPkg(pkgMap map[string]string) error {
	for url, filepath := range pkgMap {
		if err := uploadFuncPkg(url, filepath); err != nil {
			return err
		}
	}
	return nil
}

func uploadFuncPkg(url, filepath string) error {
	file, err := os.OpenFile(filepath, os.O_RDONLY, os.ModePerm)
	if err != nil {
		return err
	}
	defer func() {
		err := file.Close()
		if err != nil {
			fmt.Printf("failed to close file, err: %s\n", err.Error())
		}
	}()
	fmt.Printf("url: %s\n", url)
	req, err := http.NewRequest("PUT", url, file)
	if err != nil {
		return err
	}
	switch path.Ext(filepath) {
	case ".jpg":
		req.Header.Set("Content-Type", "image/jpeg")
	case ".zip":
		req.Header.Set("Content-Type", "application/zip")
	case ".pdf":
		req.Header.Set("Content-Type", "application/pdf")
	default:
		return errors.New("invalid file type")
	}
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer func() {
		err := res.Body.Close()
		if err != nil {
			fmt.Printf("failed to close res body\n")
		}
	}()
	if res.StatusCode != http.StatusOK {
		data, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return errors.New("upload file failed")
		}
		return errors.New("upload file failed: " + string(data))
	}
	return nil
}

func CreateClient() *dwr.DwrClient {
	client := dwr.NewDwrClient(
		dwr.DwrClientBuilder().
			WithEndpoint(endpoint).
			WithCredential(
				basic.NewCredentialsBuilder().
					WithAk(ak).
					WithSk(sk).
					WithProjectId(projectId).
					Build()).
			WithHttpConfig(config.DefaultHttpConfig().
				WithIgnoreSSLVerification(true).
				WithHttpHandler(httphandler.NewHttpHandler().AddResponseHandler(func(response http.Response) {
					fmt.Println(response.Header)
				}))).
			Build())
	return client
}

func BuildParam(templateName string) *model.ThirdTemplateRequestBody {
	templateParamName := "test"
	policyVersion := "1.1"
	actionTemplateBody := model.ThirdTemplateRequestBody{
		Category: "ImageProcess",
		Inputs: &[]model.Input{{
			ParameterName:         "test",
			Type:                  model.GetInputTypeEnum().STRING,
			TemplateParameterName: &templateParamName,
		}},
		DynamicSourceDefinition: map[string]interface{}{"test": "$.inputs.test}"},
		NeedPolicy: &[]model.Policy{{
			Version: &policyVersion,
			Statement: &[]model.Statement{{Action: &[]string{
				"obs:bucket:HeadBucket",
				"obs:bucket:ListBucketMultipartUploads",
				"obs:object:AbortMultipartUpload",
				"obs:object:PutObject",
				"obs:object:GetObject",
			}}},
		}},
		FuncProvider: map[string]string{"en-us": "dwr", "zh-cn": "数据工坊"},
		FuncName: map[string]string{"en-us": "sdk_example_action_" + strconv.FormatInt(time.Now().Unix(), 10),
			"zh-cn": "SDK示例三方算子_" + strconv.FormatInt(time.Now().Unix(), 10)},
		FuncDescription: map[string]string{"en-us": "description", "zh-cn": "描述"},
		FuncLink:        map[string]string{"en-us": "api link", "zh-cn": "http://sss"},
	}
	return &actionTemplateBody
}

// 创建三方算子并上传算子材料
func main() {
	// 1、构造client
	client := CreateClient()
	// 2、创建三方算子
	templateName := "third_create_by_sdk_" + strconv.FormatInt(time.Now().Unix(), 10)
	actionTemplateBody := BuildParam(templateName)
	res, err := client.CreateMyActionTemplate(&model.CreateMyActionTemplateRequest{
		TemplateName: templateName,
		Body:         actionTemplateBody,
	})
	if err != nil || res.HttpStatusCode != http.StatusCreated {
		fmt.Printf("failed to create my action template: %v, res: %v", err, res)
		return
	}
	templateName = *res.TemplateName
	// 3、上传算子材料
	pkgMap := map[string]string{
		*res.FuncPkgPath:                      funcPkgPath,
		res.FuncHelpPath["en-us"]:             funcHelpPathEn,
		res.FuncHelpPath["zh-cn"]:             funcHelpPathCn,
		res.FuncLogoPath["en-us"]:             funcLogoPathEn,
		res.FuncLogoPath["zh-cn"]:             funcLogoPathCn,
		res.FuncSlaPath["en-us"]:              funcSlaPathEn,
		res.FuncSlaPath["zh-cn"]:              funcSlaPathCn,
		res.FuncTestReportPath["en-us"]:       funcTestReportPathEn,
		res.FuncTestReportPath["zh-cn"]:       funcTestReportPathCn,
		res.FuncOpensourceNoticePath["en-us"]: funcOpensourceNoticePathEn,
		res.FuncOpensourceNoticePath["zh-cn"]: funcOpensourceNoticePathCn,
	}
	if err = uploadAllFuncPkg(pkgMap); err != nil {
		fmt.Printf("failed to upload func packages: %s", err.Error())
	}
	// 4、查询算子详情
	info, err := client.ShowThirdTemplateInfo(&model.ShowThirdTemplateInfoRequest{
		TemplateName: templateName,
	})
	if err != nil {
		fmt.Printf("failed to get my action template: %s", err.Error())
		return
	}
	fmt.Printf("my action template: %#v\n", info.ProvidedActions)
}
